#include "disk.h"
#include "apic.h"
#include "lib.h"
#include "printk.h"
#include "interrupt.h"

void disk_handler(unsigned long nr, unsigned long param, st_pt_regs *regs) {
    int i = 0;
    st_disk_identity_info a;
    unsigned short *p = NULL;

    PORT_INSW(PORT_DISK1_DATA, &a, 256);
    color_printk(ORANGE, WHITE, "\nSerial Number:");
    for (i = 0; i < 10; ++i) {
        color_printk(ORANGE, WHITE, "%c%c", (a.serial_num[i] >> 8) & 0xff, a.serial_num[i] & 0xff);
    }
    color_printk(ORANGE, WHITE, "\nFirmware revision:");
    for (i = 0; i < 4; ++i) {
        color_printk(ORANGE, WHITE, "%c%c", (a.firmware_ver[i] >> 8) & 0xff, a.firmware_ver[i] & 0xff);
    }
    color_printk(ORANGE, WHITE, "\nModel Number:");
    for (i = 0; i < 20; ++i) {
        color_printk(ORANGE, WHITE, "%c%c", (a.firmware_ver[i] >> 8) & 0xff, a.firmware_ver[i] & 0xff);
    }
    color_printk(ORANGE, WHITE, "\n");
    p = (unsigned short *)&a;
    for (i = 0; i < 256; ++i) {
        color_printk(ORANGE, WHITE, "%04x ", *(p + i));
    }
}

static st_hw_int_type s_disk_int_controller = {
    .enable = ioapic_enable,
    .disable = ioapic_disable,
    .install = ioapic_install,
    .uninstall = ioapic_uninstall,
    .ack = ioapic_edge_ack,
};

void disk_init() {
    st_io_apic_rte_entry entry;

    entry.vector = 0x2f;
    entry.deliver_mode = APIC_ICR_IOAPIC_FIXED;
    entry.dest_mode = ICR_IOAPIC_DELV_PHYSICAL;
    entry.deliver_status = APIC_ICR_IOAPIC_IDLE;
    entry.polarity = APIC_IOAPIC_POLARITY_HIGH;
    entry.irr = APIC_IOAPIC_IRR_RESET;
    entry.trigger = APIC_ICR_IOAPIC_EDGE;
    entry.mask = APIC_ICR_IOAPIC_MASKED;
    entry.reserved = 0;
    
    entry.destination.physical.reserved1 = 0;
    entry.destination.physical.phy_dest = 0;
    entry.destination.physical.reserved2 = 0;

    register_irq(0x2f, &entry, &disk_handler, 0, &s_disk_int_controller, "disk1");

    io_out8(PORT_DISK1_ALT_STA_CTL, 0);
    io_out8(PORT_DISK1_ERR_FEATURE, 0);
    io_out8(PORT_DISK1_SECTOR_CNT, 0);
    io_out8(PORT_DISK1_SECTOR_LOW, 0);
    io_out8(PORT_DISK1_SECTOR_MID, 0);
    io_out8(PORT_DISK1_SECTOR_HIGH, 0);
    io_out8(PORT_DISK1_DEVICE, 0xe0);       // LBA模式
    io_out8(PORT_DISK1_STATUS_CMD, 0xec);   // 获取硬盘设备信息
}

void disk_exit() {
    unregister_irq(0x2f);
}